﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Forms;
using GameDesigner.Source.Widgets;
using GameLibrary.Model;
using GameLibrary.Model.Core;
using WeifenLuo.WinFormsUI.Docking;

namespace GameDesigner.Source.Forms
{
    public partial class TreeForm : DockContent
    {
        public TreeForm()
        {
            InitializeComponent();
            
            ActiveObject.ObjectChangedEvent += this.OnObjectSelected;
            ActiveGame.GameChangedEvent += this.OnGameSelected;
            _TreeView1.AfterSelect += this.OnSelectionChanged;
            _TreeView1.Click += this.OnClick;
        }

        private void OnPlayersChange()
        {
            OnChange();
        }

        void OnElementRemovedEvent(GameElementDef subject)
        {
            OnChange();
        }

        void OnElementAddedEvent(GameElementDef subject)
        {
            OnChange();
        }

        private void OnChange()
        {
            if (ActiveGame.Game != null)
            {
                SyncGame(ActiveGame.Game);
            }
            else
            {
                _TreeView1.Nodes.Clear();
            }
        }

        private void OnGameSelected(GameDef game)
        {
            if (game != null)
            {
                SyncGame(game);
                game.GamePlayerDefs.PlayersChangedEvent += OnPlayersChange;
                game.GameElementDefs.ElementAddedEvent += OnElementAddedEvent;
                game.GameElementDefs.ElementRemovedEvent += OnElementRemovedEvent;
                game.GameTaskDefs.TaskAddedEvent += delegate(GameTaskDef player) { SyncGame(); };
                game.GameTaskDefs.TaskRemovedEvent += delegate() { SyncGame(); };
                game.GameTaskDefs.TaskChangedEvent += delegate() { SyncGame(); };
            }
            else
            {
                _TreeView1.Nodes.Clear();
            }
        }

        private void OnObjectSelected(object obj)
        {
            SyncGame();
        }

        void SyncGame()
        {
            if (ActiveGame.Game != null) 
            {
                SyncGame(ActiveGame.Game);
            } 
            else 
            {
                _TreeView1.Nodes.Clear();
            }
        }

        private void OnClick(object sender, EventArgs e)
        {
            if (_TreeView1.SelectedNode == null)
            {
                ActiveObject.Object = null;
            }
            else {
                ActiveObject.Object = _TreeView1.SelectedNode.Tag;
            }
        }

        private void OnSelectionChanged(object sender, TreeViewEventArgs e)
        {
            ActiveObject.Object = e.Node.Tag;
        }

        private void SyncGame(GameDef game)
        {
            _TreeView1.BeginUpdate();
            TreeNode root;
            TreeNode playersNode;
            TreeNode globalNode;
            TreeNode elementsNode;
            TreeNode tasksNode;
            if (_TreeView1.Nodes.Count == 0)
            {
                root = new TreeNode();
                root.Text = "Game";
                root.Tag = game;
                root.ImageIndex = 2;
                root.SelectedImageIndex = 4;

                _TreeView1.Nodes.Clear();
                _TreeView1.Nodes.Add(root);
                
                playersNode = root.Nodes.Add("Players", "Players");
                playersNode.Tag = game.GamePlayerDefs;
                playersNode.ImageIndex = 0;
                playersNode.SelectedImageIndex = 4;
                
                elementsNode = root.Nodes.Add("Elements", "Elements");
                elementsNode.Tag = game.GameElementDefs;
                elementsNode.ImageIndex = 0;
                elementsNode.SelectedImageIndex = 4;
                
                tasksNode = root.Nodes.Add("Tasks", "Tasks");
                tasksNode.Tag = game.GameTaskDefs;
                tasksNode.ImageIndex = 0;
                tasksNode.SelectedImageIndex = 4;
                
                globalNode = new TreeNode();
                globalNode = root.Nodes.Add("Global", "Global");
                globalNode.Tag = game.GlobalDef;
                globalNode.SelectedImageIndex = 4;

                root.ExpandAll();
            }
            else
            {
                root = _TreeView1.Nodes[0];
                playersNode = root.Nodes[0];
                elementsNode = root.Nodes[1];
                tasksNode = root.Nodes[2];
            }

            Sync(game, playersNode, game.GamePlayerDefs, 1);
            Sync(game, elementsNode, game.GameElementDefs, 3);
            Sync(game, tasksNode, game.GameTaskDefs, 3);

            _TreeView1.EndUpdate();
        }

        private static void Sync<T>(GameDef game, TreeNode parentNode,
                                    Collection<T> items, int imageIndex)
        {
            List<TreeNode> remove = new List<TreeNode>();
            foreach (TreeNode node in parentNode.Nodes)
            {
                bool found = false;
                foreach (HasName item in items)
                {
                    if (item.Name == node.Name)
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    remove.Add(node);
                }
            }

            foreach (TreeNode node in remove)
            {
                parentNode.Nodes.Remove(node);
            }
            
            foreach (HasName item in items)
            {
                if (item.Name == "Nothing")
                {
                    continue;
                }
                if (!parentNode.Nodes.ContainsKey(item.Name))
                {
                    TreeNode node = parentNode.Nodes.Add(item.Name, item.Name);
                    node.Text = item.Name;
                    node.Tag = item;
                    node.ImageIndex = imageIndex;
                    node.SelectedImageIndex = 4;
                    parentNode.ExpandAll();
                }
            }

        }

    }
}
